use std::{env, fs, thread};

use libunftp::notification::PresenceEvent;
use tokio::sync::{mpsc, oneshot};

use crate::ftp;

/// We derive Deserialize/Serialize so we can persist app state on shutdown.
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(default)] // if we add new fields, give them default values when deserializing old state
pub struct FtpApp {
    port: String,
    host: String,
    ftp_auth: ftp::FtpAuth,
    ftp_home: String,
    #[serde(skip)]
    session_count: u8,
    #[serde(skip)]
    shutdown_tx: Option<oneshot::Sender<u64>>,
    // 用来发送ftp server的用户事件，但是这里仅作持有clone使用，真正使用的地方在ftp server的线程
    #[serde(skip)]
    presence_notify_tx: mpsc::Sender<PresenceEvent>,
    // 用来接收ftp server的用户事件
    #[serde(skip)]
    presence_notify_rx: mpsc::Receiver<PresenceEvent>,
}

impl Default for FtpApp {
    fn default() -> Self {
        let (tx, rx) = mpsc::channel(1);
        Self {
            port: String::from("2121"),
            ftp_home: String::from("."),
            host: String::from("0.0.0.0"),
            ftp_auth: ftp::FtpAuth {
                username: String::from("sa"),
                password: String::from("sa"),
            },
            session_count: 0,
            shutdown_tx: None,
            presence_notify_rx: rx,
            presence_notify_tx: tx,
        }
    }
}

impl FtpApp {
    /// Called once before the first frame.
    pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
        // This is also where you can customize the look and feel of egui using
        // `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
        setup_custom_fonts(&cc.egui_ctx);
        // Load previous app state (if any).
        // Note that you must enable the `persistence` feature for this to work.
        if let Some(storage) = cc.storage {
            return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default();
        }

        Default::default()
    }
}

impl eframe::App for FtpApp {
    // update方法每次在发生交互都会触发（鼠标移动、点击等等），每秒可能触发很多次
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        let Self {
            host,
            port,
            ftp_auth,
            ftp_home,
            shutdown_tx: ftp_server,
            session_count,
            presence_notify_rx,
            presence_notify_tx,
        } = self;

        if let Ok(presence_notify) = presence_notify_rx.try_recv() {
            match presence_notify {
                PresenceEvent::LoggedIn => *session_count += 1,
                PresenceEvent::LoggedOut => if *session_count > 0 { *session_count -= 1 },
            }
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            egui::Grid::new("my grid")
                .num_columns(2)
                .spacing([40.0, 9.0])
                .striped(true)
                .show(ui, |ui| {
                    // ui.heading("服务参数");
                    ui.label(" 侦听端口:");
                    ui.text_edit_singleline(port);
                    ui.end_row();

                    ui.label(" 侦听地址:");
                    ui.text_edit_singleline(host);
                    ui.end_row();

                    ui.label(" 用户:");
                    ui.text_edit_singleline(&mut ftp_auth.username);
                    ui.end_row();

                    ui.label(" 密码:");
                    ui.text_edit_singleline(&mut ftp_auth.password);
                    ui.end_row();

                    if ui.button("共享目录:").clicked() {
                        if let Some(path) = rfd::FileDialog::new().pick_folder() {
                            *ftp_home = path.display().to_string();
                        }
                    }
                    ui.text_edit_singleline(ftp_home);
                    ui.end_row();

                    ui.horizontal(|ui| {
                        if ui.button("启动").clicked() {
                            if ftp_server.is_none() {
                                // 启动时创建个一次性管道
                                let (tx, rx) = oneshot::channel();
                                // 首次启动连接数一定为0
                                *session_count = 0;
                                ftp_server.replace(tx);
                                let ftp_config = ftp::FtpConfig {
                                    ftp_home: ftp_home.to_string(),
                                    port: port.to_string(),
                                    host: host.to_string(),
                                    ftp_auth: ftp_auth.clone(),
                                    shutdown_rx: rx,
                                    presence_notify_tx: presence_notify_tx.clone(),
                                    ctx: ctx.clone(),
                                };

                                thread::spawn(|| {
                                    ftp::run_ftp(ftp_config);
                                });
                            }
                        }
                        if ui.button("停止").clicked() {
                            if let Some(tx) = ftp_server.take() {
                                tx.send(0).unwrap();
                                *session_count = 0;
                            }
                        }
                    });
                    ui.end_row();
                });

            // ui.add_space(10.0);
            // ui.vertical_centered(|ui| {
            //     ui.group(|ui| {
            //         ui.set_height(130.0);
            //         ui.text_edit_multiline(&mut "连接成功!");
            //     });
            // });
            ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
                ui.horizontal(|ui| {
                    ui.spacing_mut().item_spacing.x = 0.0;
                    ui.label("状态: ");
                    let _ = ui.link(
                        if ftp_server.is_some() { "启动" } else { "停止" }
                    );
                    ui.add_space(10.0);
                    ui.label("连接数: ");
                    let _ = ui.link(format!("{}", session_count));
                });
            });
        });
    }

    /// Called by the frame work to save state before shutdown.
    fn save(&mut self, storage: &mut dyn eframe::Storage) {
        eframe::set_value(storage, eframe::APP_KEY, self);
    }
}

///全局加载支持中文的字体

pub fn setup_custom_fonts(ctx: &egui::Context) {
    let mut fonts = eframe::egui::FontDefinitions::default();

    #[cfg(target_os = "windows")]
        let font_path = format!("{}\\Fonts\\msyh.ttc", env::var("SYSTEMROOT").unwrap());

    #[cfg(target_os = "linux")]
        let font_path = String::from("/usr/share/fonts");

    let font_byte = fs::read(font_path);
    // Install my own font (maybe supporting non-latin characters):
    fonts.font_data.insert("msyh".to_owned(),
                           eframe::egui::FontData::from_owned(font_byte.unwrap())); // .ttf and .otf supported

    // Put my font first (highest priority):
    fonts.families.get_mut(&eframe::egui::FontFamily::Proportional).unwrap()
        .insert(0, "msyh".to_owned());

    // Put my font as last fallback for monospace:
    fonts.families.get_mut(&eframe::egui::FontFamily::Monospace).unwrap()
        .push("msyh".to_owned());

    // let mut ctx = egui::CtxRef::default();
    ctx.set_fonts(fonts);
}